package com.jie.flink.cdc.util;

import lombok.NonNull;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.BiFunction;
import java.util.function.Function;

/**
 * @author zhanggj
 * @data 2022/5/30
 */
public class JsonUtils {

    private static final String CONVERTOR_IS_NULL_ERROR_MESSAGE = "jsonConvertor is null please set JsonConvertor before use";

    /**
     * 默认解析器
     */
    private static JsonConvertor jsonConvertor = new JacksonConvertor();

    public static BeanConvertor getJsonConvertor() {
        return jsonConvertor;
    }

    public static void setJsonConvertor(JsonConvertor jsonConvertor) {
        JsonUtils.jsonConvertor = jsonConvertor;
    }

    /**
     * 通过指定 biFunction json 转换
     *
     * @param biFunction
     * @param map
     * @param classOfT
     * @param <T>
     * @return
     */
    public static <T> T mapToObject(@NonNull BiFunction<Map<String,Object>,Class<T>,T> biFunction, Map<String, Object> map, Class<T> classOfT) {
        return biFunction.apply(map,classOfT);

    }

    /**
     * 通过指定 biFunction json 转换
     *
     * @param biFunction
     * @param map
     * @param type
     * @param <T>
     * @return
     */
    public static <T> T mapToObject(@NonNull BiFunction<Map<String,Object>, Type,T> biFunction, Map<String, Object> map, Type type) {
        return biFunction.apply(map,type);
    }

    /**
     * 使用 defaultJsonConvertor json 转换
     *
     * @param map
     * @param classOfT
     * @param <T>
     * @return
     */
    public static <T> T mapToObject(Map<String, Object> map, Class<T> classOfT) {
        if(Objects.isNull(jsonConvertor)) {
            throw new UnsupportedOperationException(CONVERTOR_IS_NULL_ERROR_MESSAGE);
        }
        return mapToObject((BiFunction<Map<String, Object>, Class<T>, T>) (t, u) -> {
            try {
                return (T) jsonConvertor.convertToBean(t,u);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }, map, classOfT);
    }


    /**
     * 使用 defaultJsonConvertor json 转换
     *
     * @param map
     * @param type
     * @param <T>
     * @return
     */
    public static <T> T mapToObject(Map<String, Object> map, Type type) {
        if(Objects.isNull(jsonConvertor)) {
            throw new UnsupportedOperationException(CONVERTOR_IS_NULL_ERROR_MESSAGE);
        }
        return mapToObject((t, u) -> {
            try {
                return (T) jsonConvertor.convertToBean(t,u);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }, map, type);

    }


    /**
     * 使用 defaultJsonConvertor json 转换
     *
     * @param jsonString
     * @param classOfT
     * @param <T>
     * @return
     */
    public static <T> T stringToObject(String jsonString, Class<T> classOfT) {
        if(Objects.isNull(jsonConvertor)) {
            throw new UnsupportedOperationException(CONVERTOR_IS_NULL_ERROR_MESSAGE);
        }
        return stringToObject((BiFunction<String, Class<T>, T>) (t, u) -> {
            try {
                return (T) jsonConvertor.deserialize(t,u);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }, jsonString, classOfT);
    }

    /**
     * json字符串转换
     *
     * @param biFunction
     * @param jsonString
     * @param classOfT
     * @param <T>
     * @return
     */
    public static <T> T stringToObject(@NonNull BiFunction<String,Class<T>,T> biFunction, String jsonString, Class<T> classOfT) {
        if (StringUtils.isBlank(jsonString)) {
            return null;
        }
        return biFunction.apply(jsonString,classOfT);
    }

    /**
     * 使用 defaultJsonConvertor json 转换
     *
     * @param jsonString
     * @param type
     * @return
     */
    public static <T> T stringToObject(String jsonString, Type type) {
        if(Objects.isNull(jsonConvertor)) {
            throw new UnsupportedOperationException(CONVERTOR_IS_NULL_ERROR_MESSAGE);
        }
        return stringToObject((t,u)->{
            try {
                return jsonConvertor.deserialize(t,u);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }, jsonString, type);
    }

    public static <T> T stringToObject(@NonNull BiFunction<String,Type,T> biFunction, String jsonString, Type type)  {
        if (StringUtils.isBlank(jsonString)) {
            return null;
        }
        return biFunction.apply(jsonString,type);
    }


    public static Map<String, Object> toJSONMap(Object object) {
        if(Objects.isNull(jsonConvertor)) {
            throw new UnsupportedOperationException(CONVERTOR_IS_NULL_ERROR_MESSAGE);
        }
        return toJSONMap(t->{
            try {
                return jsonConvertor.convertToMap(t);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }, object);
    }

    public static Map<String, Object> toJSONMap(@NonNull Function<Object,Map<String,Object>> function, Object object) {
        return function.apply(object);
    }

    public static Map<String, Object> toJSONMap(String jsonString) {
        if(Objects.isNull(jsonConvertor)) {
            throw new UnsupportedOperationException(CONVERTOR_IS_NULL_ERROR_MESSAGE);
        }
        return toJSONMap((Function<String,Map<String,Object>>)(t)->{
            try {
                return jsonConvertor.convertToMap(t);
            }catch (Exception e){
                throw new RuntimeException(e);
            }
        }, jsonString);
    }

    public static Map<String, Object> toJSONMap(@NonNull Function<String,Map<String,Object>> function, String jsonString) {
        if (StringUtils.isBlank(jsonString)) {
            return null;
        }
        return function.apply(jsonString);
    }


    public static <T> List<T> toJSONArray(String jsonString, Class<T> classOfT) {
        if(Objects.isNull(jsonConvertor)) {
            throw new UnsupportedOperationException(CONVERTOR_IS_NULL_ERROR_MESSAGE);
        }
        return toJSONArray((BiFunction<String,Class<T>,List<T>>)(t,u)->{
            try {
                return jsonConvertor.deserializeToArray(t,u);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }, jsonString,classOfT);
    }

    public static <T> List<T> toJSONArray(@NonNull BiFunction<String,Class<T>,List<T>> biFunction, String jsonString,Class<T> classOfT) {
        if (StringUtils.isBlank(jsonString)) {
            return null;
        }
        return biFunction.apply(jsonString,classOfT);
    }


    public static <T> List<T> toJSONArray(String jsonString,Type type) {
        if(Objects.isNull(jsonConvertor)) {
            throw new UnsupportedOperationException(CONVERTOR_IS_NULL_ERROR_MESSAGE);
        }
        return toJSONArray((t,u)->{
            try {
                return jsonConvertor.deserializeToArray(t,u);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }, jsonString,type);
    }

    public static <T> List<T> toJSONArray(@NonNull BiFunction<String,Type,List<T>> biFunction, String jsonString,Type type) {
        if (StringUtils.isBlank(jsonString)) {
            return null;
        }
        return biFunction.apply(jsonString,type);
    }

    public static String toJSONString(Object object) {
        if(Objects.isNull(jsonConvertor)) {
            throw new UnsupportedOperationException(CONVERTOR_IS_NULL_ERROR_MESSAGE);
        }
        return toJSONString(t->{
            try {
                return jsonConvertor.serialize(object);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }, object);
    }

    public static String toJSONString(@NonNull Function<Object,String> function, Object object) {
        if (Objects.isNull(object)) {
            return null;
        }
        return function.apply(object);
    }

    /**
     * json字符串转成对象，转换前先简单校验是否为json，转换不成功返回为空
     * @param jsonString
     * @param classOfT
     * @param <T>
     * @return
     */
    public static <T> T stringToObjectWithCheck(String jsonString, Class<T> classOfT) {
        if (StringUtils.isEmpty(jsonString)) {
            return null;
        }
        if (!jsonString.startsWith("{") || !jsonString.endsWith("}")) {
            return null;
        }

        try {
            return stringToObject(jsonString, classOfT);
        } catch (Exception e) {
            return null;
        }
    }
}
